home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 23 / Amiga Format AFCD23 (Feb 1998, Issue 107).iso / -in_the_mag- / emulation / consoles / vision-8 / sources / chip8.c < prev    next >
C/C++ Source or Header  |  1997-12-12  |  8KB  |  383 lines

  1. /** Vision8: CHIP8 emulator *************************************************/
  2. /**                                                                        **/
  3. /**                                CHIP8.c                                 **/
  4. /**                                                                        **/
  5. /** This file contains the portable CHIP8 emulation engine                 **/
  6. /**                                                                        **/
  7. /** Copyright (C) Marcel de Kogel 1997                                     **/
  8. /**     You are not allowed to distribute this software commercially       **/
  9. /**     Please, notify me, if you make any changes to this file            **/
  10. /****************************************************************************/
  11.  
  12. #include "CHIP8.h"
  13.  
  14. #include <stdlib.h>
  15. #include <string.h>
  16.  
  17. byte chip8_mem[4096];
  18. #define read_mem(a)     (chip8_mem[(a)&4095])
  19. #define write_mem(a,v)  (chip8_mem[(a)&4095]=(v))
  20.  
  21. byte chip8_iperiod;
  22.  
  23. #ifdef DEBUG
  24. byte chip8_trace;
  25. word chip8_trap;
  26. #endif
  27.  
  28. struct chip8_regs_struct chip8_regs;
  29.  
  30. static byte chip8_key_pressed;
  31. byte chip8_keys[16];
  32. byte chip8_display[64*32];
  33. byte chip8_running;
  34.  
  35. #define get_reg_offset(opcode)          (chip8_regs.alg+(opcode>>8))
  36. #define get_reg_value(opcode)           (*get_reg_offset(opcode))
  37. #define get_reg_offset_2(opcode)        (chip8_regs.alg+((opcode>>4)&0x0f))
  38. #define get_reg_value_2(opcode)         (*get_reg_offset_2(opcode))
  39.  
  40. typedef void (*opcode_fn) (word opcode);
  41. typedef void (*math_fn) (byte *reg1,byte reg2);
  42.  
  43. static void op_call (word opcode)
  44. {
  45.  chip8_regs.sp--;
  46.  write_mem (chip8_regs.sp,chip8_regs.pc&0xff);
  47.  chip8_regs.sp--;
  48.  write_mem (chip8_regs.sp,chip8_regs.pc>>8);
  49.  chip8_regs.pc=opcode;
  50. }
  51.  
  52. static void op_jmp (word opcode)
  53. {
  54.  chip8_regs.pc=opcode;
  55. }
  56.  
  57. static void op_key (word opcode)
  58. {
  59.  byte key_value,cp_value;
  60.  if ((opcode&0xff)==0x9e)
  61.   cp_value=1;
  62.  else if ((opcode&0xff)==0xa1)
  63.   cp_value=0;
  64.  else
  65.   return;
  66.  key_value=chip8_keys[get_reg_value(opcode)&0x0f];
  67.  if (cp_value==key_value) chip8_regs.pc+=2;
  68. }
  69.  
  70. static void op_skeq_const (word opcode)
  71. {
  72.  if (get_reg_value(opcode)==(opcode&0xff)) chip8_regs.pc+=2;
  73. }
  74.  
  75. static void op_skne_const (word opcode)
  76. {
  77.  if (get_reg_value(opcode)!=(opcode&0xff)) chip8_regs.pc+=2;
  78. }
  79.  
  80. static void op_skeq_reg (word opcode)
  81. {
  82.  if (get_reg_value(opcode)==get_reg_value_2(opcode)) chip8_regs.pc+=2;
  83. }
  84.  
  85. static void op_skne_reg (word opcode)
  86. {
  87.  if (get_reg_value(opcode)!=get_reg_value_2(opcode)) chip8_regs.pc+=2;
  88. }
  89.  
  90. static void op_mov_const (word opcode)
  91. {
  92.  *get_reg_offset(opcode)=opcode&0xff;
  93. }
  94.  
  95. static void op_add_const (word opcode)
  96. {
  97.  *get_reg_offset(opcode)+=opcode&0xff;
  98. }
  99.  
  100. static void op_mvi (word opcode)
  101. {
  102.  chip8_regs.i=opcode;
  103. }
  104.  
  105. static void op_jmi (word opcode)
  106. {
  107.  chip8_regs.pc=opcode+chip8_regs.alg[0];
  108. }
  109.  
  110. static void op_rand (word opcode)
  111. {
  112.  *get_reg_offset(opcode)=rand()&(opcode&0xff);
  113. }
  114.  
  115. static void math_or (byte *reg1,byte reg2)
  116. {
  117.  *reg1|=reg2;
  118. }
  119.  
  120. static void math_mov (byte *reg1,byte reg2)
  121. {
  122.  *reg1=reg2;
  123. }
  124.  
  125. static void math_nop (byte *reg1,byte reg2)
  126. {
  127. }
  128.  
  129. static void math_and (byte *reg1,byte reg2)
  130. {
  131.  *reg1&=reg2;
  132. }
  133.  
  134. static void math_xor (byte *reg1,byte reg2)
  135. {
  136.  *reg1^=reg2;
  137. }
  138.  
  139. static void math_add (byte *reg1,byte reg2)
  140. {
  141.  word tmp;
  142.  tmp=*reg1+reg2;
  143.  *reg1=(byte)tmp;
  144.  chip8_regs.alg[15]=tmp>>8;
  145. }
  146.  
  147. static void math_sub (byte *reg1,byte reg2)
  148. {
  149.  word tmp;
  150.  tmp=*reg1-reg2;
  151.  *reg1=(byte)tmp;
  152.  chip8_regs.alg[15]=((byte)(tmp>>8))+1;
  153. }
  154.  
  155. static void math_shr (byte *reg1,byte reg2)
  156. {
  157.  chip8_regs.alg[15]=*reg1&1;
  158.  *reg1>>=1;
  159. }
  160.  
  161. static void math_shl (byte *reg1,byte reg2)
  162. {
  163.  chip8_regs.alg[15]=*reg1>>7;
  164.  *reg1<<=1;
  165. }
  166.  
  167. static void math_rsb (byte *reg1,byte reg2)
  168. {
  169.  word tmp;
  170.  tmp=reg2-*reg1;
  171.  *reg1=(byte)tmp;
  172.  chip8_regs.alg[15]=((byte)(tmp>>8))+1;
  173. }
  174.  
  175. static void op_system (word opcode)
  176. {
  177.  switch ((byte)opcode)
  178.  {
  179.   case 0xe0:
  180.    memset (chip8_display,0,sizeof(chip8_display));
  181.    break;
  182.   case 0xee:
  183.    chip8_regs.pc=read_mem(chip8_regs.sp)<<8;
  184.    chip8_regs.sp++;
  185.    chip8_regs.pc+=read_mem(chip8_regs.sp);
  186.    chip8_regs.sp++;
  187.    break;
  188.  }
  189. }
  190.  
  191. static void op_misc (word opcode)
  192. {
  193.  byte *reg,i,j;
  194.  reg=get_reg_offset(opcode);
  195.  switch ((byte)opcode)
  196.  {
  197.   case 0x07:
  198.    *reg=chip8_regs.delay;
  199.    break;
  200.   case 0x0a:
  201.    if (chip8_key_pressed)
  202.     *reg=chip8_key_pressed-1;
  203.    else
  204.     chip8_regs.pc-=2;
  205.    break;
  206.   case 0x15:
  207.    chip8_regs.delay=*reg;
  208.    break;
  209.   case 0x18:
  210.    chip8_regs.sound=*reg;
  211.    if (chip8_regs.sound) chip8_sound_on();
  212.    break;
  213.   case 0x1e:
  214.    chip8_regs.i+=(*reg);
  215.    break;
  216.   case 0x29:
  217.    chip8_regs.i=((word)(*reg&0x0f))*5;
  218.    break;
  219.   case 0x33:
  220.    i=*reg;
  221.    for (j=0;i>=100;i-=100) j++;
  222.    write_mem (chip8_regs.i,j);
  223.    for (j=0;i>=10;i-=10) j++;
  224.    write_mem (chip8_regs.i+1,j);
  225.    write_mem (chip8_regs.i+2,i);
  226.    break;
  227.   case 0x55:
  228.    for (i=0,j=(opcode>>8)&0x0f;i<=j;++i)
  229.     write_mem(chip8_regs.i+i,chip8_regs.alg[i]);
  230.    break;
  231.   case 0x65:
  232.    for (i=0,j=(opcode>>8)&0x0f;i<=j;++i)
  233.     chip8_regs.alg[i]=read_mem(chip8_regs.i+i);
  234.    break;
  235.  }
  236. }
  237.  
  238. static void op_sprite (word opcode)
  239. {
  240.  byte *q;
  241.  byte n,x,x2,y,collision;
  242.  word p;
  243.  x=get_reg_value(opcode)&63;
  244.  y=get_reg_value_2(opcode)&31;
  245.  p=chip8_regs.i;
  246.  q=chip8_display+y*64;
  247.  n=opcode&0x0f;
  248.  if (n+y>32) n=32-y;
  249.  for (collision=1;n;--n,q+=64)
  250.  {
  251.   for (y=read_mem(p++),x2=x;y;y<<=1,x2=(x2+1)&63)
  252.    if (y&0x80) collision&=(q[x2]^=0xff);
  253.  }
  254.  chip8_regs.alg[15]=collision^1;
  255. }
  256.  
  257. static math_fn math_opcodes[16]=
  258. {
  259.  math_mov,
  260.  math_or,
  261.  math_and,
  262.  math_xor,
  263.  math_add,
  264.  math_sub,
  265.  math_shr,
  266.  math_rsb,
  267.  math_nop,
  268.  math_nop,
  269.  math_nop,
  270.  math_nop,
  271.  math_nop,
  272.  math_nop,
  273.  math_shl,
  274.  math_nop
  275. };
  276.  
  277. static void op_math (word opcode)
  278. {
  279.  (*(math_opcodes[opcode&0x0f]))
  280.         (get_reg_offset(opcode),get_reg_value_2(opcode));
  281. }
  282.  
  283. static opcode_fn main_opcodes[16]=
  284. {
  285.  op_system,
  286.  op_jmp,
  287.  op_call,
  288.  op_skeq_const,
  289.  op_skne_const,
  290.  op_skeq_reg,
  291.  op_mov_const,
  292.  op_add_const,
  293.  op_math,
  294.  op_skne_reg,
  295.  op_mvi,
  296.  op_jmi,
  297.  op_rand,
  298.  op_sprite,
  299.  op_key,
  300.  op_misc
  301. };
  302.  
  303. /****************************************************************************/
  304. /* Execute chip8_iperiod opcodes                                            */
  305. /****************************************************************************/
  306. void chip8_execute (void)
  307. {
  308.  byte i;
  309.  byte key_pressed=0;
  310.  word opcode;
  311.  for (i=chip8_iperiod;i;--i)
  312.  {
  313.   /* Fetch the opcode */
  314.   opcode=(read_mem(chip8_regs.pc)<<8)+read_mem(chip8_regs.pc+1);
  315. #ifdef DEBUG
  316.   /* Check if trap address has been reached */
  317.   if ((chip8_regs.pc&4095)==chip8_trap) chip8_trace=1;
  318.   /* Call the debugger if chip8_trace!=0 */
  319.   if (chip8_trace) chip8_debug (opcode,&chip8_regs);
  320. #endif
  321.   chip8_regs.pc+=2;
  322.   /* Emulate this opcode */
  323.   (*(main_opcodes[opcode>>12]))(opcode&0x0fff);
  324.  }
  325.  /* Update timers */
  326.  if (chip8_regs.delay) --chip8_regs.delay;
  327.  if (chip8_regs.sound)
  328.   if (!--chip8_regs.sound) chip8_sound_off();
  329.  /* Update the machine status */
  330.  chip8_interrupt ();
  331.  for (i=key_pressed=0;i<16;++i)                 /* check if a key was first */
  332.   if (chip8_keys[i]) key_pressed=i+1;           /* pressed                  */
  333.  if (key_pressed && key_pressed!=chip8_key_pressed)
  334.   chip8_key_pressed=key_pressed;
  335.  else
  336.   chip8_key_pressed=0;
  337. }
  338.  
  339. /****************************************************************************/
  340. /* Reset the virtual chip8 machine                                          */
  341. /****************************************************************************/
  342. void chip8_reset (void)
  343. {
  344.  static byte chip8_sprites[16*5]=
  345.  {
  346.   0xf9,0x99,0xf2,0x62,0x27,
  347.   0xf1,0xf8,0xff,0x1f,0x1f,
  348.   0x99,0xf1,0x1f,0x8f,0x1f,
  349.   0xf8,0xf9,0xff,0x12,0x44,
  350.   0xf9,0xf9,0xff,0x9f,0x1f,
  351.   0xf9,0xf9,0x9e,0x9e,0x9e,
  352.   0xf8,0x88,0xfe,0x99,0x9e,
  353.   0xf8,0xf8,0xff,0x8f,0x88,
  354.  };
  355.  byte i;
  356.  for (i=0;i<16*5;++i)
  357.  {
  358.   write_mem (i<<1,chip8_sprites[i]&0xf0);
  359.   write_mem ((i<<1)+1,chip8_sprites[i]<<4);
  360.  }
  361.  memset (chip8_regs.alg,0,sizeof(chip8_regs.alg));
  362.  memset (chip8_keys,0,sizeof(chip8_keys));
  363.  chip8_key_pressed=0;
  364.  memset (chip8_display,0,sizeof(chip8_display));
  365.  chip8_regs.delay=chip8_regs.sound=chip8_regs.i=0;
  366.  chip8_regs.sp=0x1e0;
  367.  chip8_regs.pc=0x200;
  368.  chip8_sound_off ();
  369.  chip8_running=1;
  370. #ifdef DEBUG
  371.  chip8_trace=0;
  372. #endif
  373. }
  374.  
  375. /****************************************************************************/
  376. /* Start CHIP8 emulation                                                    */
  377. /****************************************************************************/
  378. void chip8 (void)
  379. {
  380.  chip8_reset ();
  381.  while (chip8_running) chip8_execute ();
  382. }
  383.